import React, { useRef, useEffect, useState } from "react";
import * as monaco from "monaco-editor";
import _ from "lodash";
import Loading from "./Loading";
import moment from "moment";
import useInterval from "./hooks/useInterval"

export default function JavascriptEditor(props: {
  defaultValue: string;
  defaultEnableAutoSave?: boolean;
  autoSaveInterval?: number;
  saveButtonText?: string;
  onSave?: (value: string) => Promise<void> | void;
}) {
  const {
    defaultValue,
    defaultEnableAutoSave = false,
    autoSaveInterval = 5 * 1000,
    saveButtonText = "保存",
    onSave,
  } = props;

  const divEl = useRef<HTMLDivElement>(null);

  const editorRef = useRef<monaco.editor.IStandaloneCodeEditor>();

  const [loading, updateLoading] = useState<boolean>(false);

  const [lastUpdateTime, updateLastUpdateTime] = useState<string>(
    moment().format("HH:mm:ss")
  );

  const [modified, updateModified] = useState<boolean>(false);

  const [enableAutoSave, updateEnableAutoSave] = useState<boolean>(defaultEnableAutoSave);

  useEffect(() => {
    if (divEl.current) {
      editorRef.current = monaco.editor.create(divEl.current, {
        value: defaultValue,
        language: "javascript",
        theme: "vs-dark",
        minimap: {
          enabled: false
        }
      });

      editorRef.current.onDidChangeModelContent((e) => {
        updateModified(true);
      });
      editorRef.current.onKeyDown((e) => {
        if (e.ctrlKey && e.keyCode === 49) {
          e.preventDefault();
          // ctrl + s
          if (onSave) {
            const editor = editorRef.current;

            const ret = onSave(editor ? editor.getValue() : "");
            if (ret && ret.then) {
              updateLoading(true);
              ret.then(() => {
                updateLoading(false);
                updateLastUpdateTime(moment().format("HH:mm:ss"));
                updateModified(false);
              });
            } else {
              updateLastUpdateTime(moment().format("HH:mm:ss"));
              updateModified(false);
            }
          }
        }
      });

      editorRef.current.layout();
    }
    return () => {
      editorRef.current?.dispose();
    };
  }, []);

  // autoLayout
  useEffect(() => {
    const layout = () => {
      const editor = editorRef.current;
      if (editor) {
        editor.layout();
      }
    };

    const debounedLayout = _.debounce(layout, 500);

    window.addEventListener("resize", debounedLayout);

    return () => {
      window.removeEventListener("resize", debounedLayout);
    };
  }, []);

  // autoSave
  useInterval(function(){
    if (onSave && modified) {
      const editor = editorRef.current;
      const ret = onSave(editor ? editor.getValue() : "");
      if (ret && ret.then) {
        updateLoading(true);
        ret.then(() => {
          updateLoading(false);
          updateLastUpdateTime(moment().format("HH:mm:ss"));
          updateModified(false);
        });
      } else {
        updateLastUpdateTime(moment().format("HH:mm:ss"));
        updateModified(false);
      }
    }
  }, enableAutoSave ? autoSaveInterval : null);

  const handleClick = () => {
    const editor = editorRef.current;

    if (onSave) {
      const ret = onSave(editor ? editor.getValue() : "");
      if (ret && ret.then) {
        updateLoading(true);
        ret.then(() => {
          updateLoading(false);
          updateLastUpdateTime(moment().format("HH:mm:ss"));
          updateModified(false);
        });
      } else {
        updateLastUpdateTime(moment().format("HH:mm:ss"));
        updateModified(false);
      }
    }
  };

  return (
    <div className={"lowcode-editor-container"}>
      <div className={"lowcode-editor-control-panel"}>
        <div className={"editor-info"}>
          {modified ? (
            <span>代码已修改，可按 Ctrl+S 保存</span>
          ) : (
              <>
                <span className="time">{lastUpdateTime}</span>
                <span className="info">代码已运行</span>
              </>
            )}
        </div>
        <div className={"editor-controls"}>
          <span className={"editor-controls-autosave"}>
            <label><input type={"checkbox"} checked={enableAutoSave} onChange={(e) => updateEnableAutoSave(!enableAutoSave)}></input>自动保存(间隔5s)</label>
          </span>
          <div className={"editor-controls-btn"} onClick={handleClick}>
            {loading ? <Loading /> : <span>{saveButtonText}</span>}
            {modified ? (
              <span style={{ color: "red", marginLeft: 4 }}>*</span>
            ) : null}
          </div>
        </div>
      </div>
      <div className={"lowcode-editor-main"} >
        <div className={"lowcode-editor"} ref={divEl}></div>
      </div>
    </div>
  );
}
